package de.islanders.unit.player.inventory;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

//TODO needs static handling for bagSlot automation

public class ItemHandler {
	public static final int EQUIPSLOT_HEAD = 0,
							EQUIPSLOT_SHOULDERS = 1,
							EQUIPSLOT_CHEST = 2,
							EQUIPSLOT_WRIST = 3,
							EQUIPSLOT_HANDS = 4,
							EQUIPSLOT_WAIST = 5,
							EQUIPSLOT_LEGS = 6,
							EQUIPSLOT_FEET = 7,
							EQUIPSLOT_RHAND = 8,
							EQUIPSLOT_LHAND = 9,
							EQUIPSLOT_NUM = 10;
	
	private static int slotCount;
	private static LinkedList<Integer> skips;
	
	static {
		slotCount = 0;
		skips = new LinkedList<Integer>();
	}
	
	private List<PropertyChangeListener> listeners;
	private final Encumbrance encumbrance;
	private Map<Integer, InventoryItem> inventoryItems;
	private Map<Integer, EquippedItem> equippedItems;
	
	public ItemHandler() {
		encumbrance = new Encumbrance(this);
		listeners = new ArrayList<PropertyChangeListener>();
		equippedItems = new Hashtable<Integer, EquippedItem>(EQUIPSLOT_NUM+1, 1f);
		
		listeners.add(encumbrance);
	}
	
	public Encumbrance getEncumbrance() {
		return encumbrance;
	}

	private void notifyListeners(String propertyName, Object oldValue, Object newValue) {
		for(PropertyChangeListener pcl : listeners) {
			pcl.propertyChange(new PropertyChangeEvent(this, propertyName, oldValue, newValue));
		}
	}
	
	@SuppressWarnings("unchecked")
	public Map<Integer, InventoryItem> getInventory() {
		return (this.inventoryItems == null
				? Collections.EMPTY_MAP
				: Collections.unmodifiableMap(this.inventoryItems));
	}
	
	@SuppressWarnings("unchecked")
	public Map<Integer, EquippedItem> getEquippedItems() {
		return (this.equippedItems.size() == 0
				? Collections.EMPTY_MAP
				: Collections.unmodifiableMap(this.equippedItems));
	}
	
	public int getInventorySize() {
		return inventoryItems.size();
	}
	
	//TODO some findInventoryItem overloads for finding by name, etc
	public InventoryItem findInventoryItem(int bagSlot) {
		if(inventoryItems != null && inventoryItems.containsKey(bagSlot)) {
			return inventoryItems.get(bagSlot);
		}
		return null;
	}
	
	//TODO needs implementation for adding more items to stack
	public void bagItem(InventoryItem item) {
		if(item != null) {
			if (inventoryItems == null) {
				inventoryItems = new Hashtable<Integer, InventoryItem>();
			}
			int bagSlot = skips.isEmpty() ? slotCount++ : skips.pollFirst();
			inventoryItems.put(bagSlot, item);
			notifyListeners("bagItem()", null, item);
		}
	}
	
	public boolean dropItem(InventoryItem item) {
		return dropItem(item.getBagSlot());
	}
	
	public boolean dropItem(int bagSlot) {
		if(inventoryItems != null) {
			if(inventoryItems.containsKey(bagSlot)) {
				notifyListeners("dropItem()", inventoryItems.remove(bagSlot), null);
				skips.add(bagSlot);
			}
			return true;
		}
		return false;
	}
	
	public EquippedItem getEquippedItem(int equipSlot) {
		return equippedItems.get(equipSlot);
	}
	
	public boolean hasSlotEquipped(int equipSlot) {
		return equippedItems.containsKey(equipSlot);
	}
	
	public InventoryItem unequipItem(int equipSlot) {
		if(equippedItems.containsKey(equipSlot)) {
			InventoryItem item = equippedItems.remove(equipSlot).toInventoryItem();
			if(item != null) {
				bagItem(item);
				return item;
			}
		}
		return null;
	}
	
	//TODO InventoryItem really the best thing here? Maybe we need a more generalized version of GameObject
	public void equipItem(InventoryItem item) {
		InventoryItem old = unequipItem(item.getEquipSlot());
		bagItem(old);
		equippedItems.put(item.getEquipSlot(), item.toEquippedItem());
	}
}
